package com.health.mapp.service;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.text.ParseException;
import java.util.Date;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.codec.binary.Base64;
import org.apache.log4j.Logger;
import org.codehaus.jackson.JsonParseException;
import org.codehaus.jackson.map.DeserializationConfig;
import org.codehaus.jackson.map.JsonMappingException;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.map.SerializationConfig;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.health.commons.CommonsUtils;
import com.health.db.model.ReqLog;
import com.health.mapp.bean.Header;
import com.health.mapp.exception.MappException;
import com.health.mapp.impl.ActionInterface;
import com.health.mapp.impl.HeaderCheckImpl;
import com.health.mapp.utils.Constant;
import com.health.mapp.utils.DateUtils;
import com.health.mapp.utils.DefaultResponse;
import com.health.mapp.utils.Response;
import com.health.redis.RedisClient;

public class Adapter<T> {

	private static Logger logger = Logger.getLogger(Adapter.class);
	private HttpServletRequest request;
	
	public HttpServletRequest getRequest() {
		return request;
	}

	public void setRequest(HttpServletRequest request) {
		this.request = request;
	}

	/**
	 * @param len
	 *           数据长度
	 * @param buffer
	 *           数据BUFF
	 * @return
	 */
	public String execute(int len, byte[] buffer) {

		//定义返回结果
		String resultJson = null;
		
		String userAgent = request.getHeader("user-agent");

		String referer = request.getHeader("referer");
		
		logger.debug("userAgent:"+userAgent +";referer:"+referer);
		String remoteIP ="";
		try {
			remoteIP = SecureUtil.getRemoteHost(request);
		} catch (IOException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
		
		//是否使用ECB加密
		boolean useECBCrypto = false;
		
		//报方头对象
		Header headerInfo = new Header();
		//报文体存储空间
		byte[] jsonBuffer = null;
		//logger.debug("input HEADER_SIZE:"+len);
		
		//判断输入的数据是否大于规定的头部长度，如果头部长度未达到，说明数据异常
		if (len > Constant.HEADER_SIZE) 
		{

			//准备头部读取存储空间
			byte[] headBuffer = new byte[Constant.HEADER_SIZE + 1];
			//将头部数据读出来
			System.arraycopy(buffer, 0, headBuffer, 0, Constant.HEADER_SIZE);
			
			//头部数据最后一个byte填充为0
			headBuffer[Constant.HEADER_SIZE] = 0;

			//准备好报文体部分的存储空间
			jsonBuffer = new byte[len - Constant.HEADER_SIZE];
			//将头部之后的数据(报文体)读出来
			System.arraycopy(buffer, Constant.HEADER_SIZE, jsonBuffer, 0, len
					- Constant.HEADER_SIZE);
		//	logger.debug("jsonBuffer: "			+ jsonBuffer.toString());
//			try {
//				logger.info("request:"+new String(jsonBuffer, "UTF-8"));
//			} catch (UnsupportedEncodingException e1) {
//				// TODO Auto-generated catch block
//				e1.printStackTrace();
//			}
			String[] headerStrList = null;
			try {
				//将头部数据处理为Key=value的字符串数组
				headerStrList = new String(headBuffer, "UTF-8").split("&");
			} catch (UnsupportedEncodingException e) {
				logger.error(Constant.MSG_HEADER_ERR);
				logger.error("Request  [" + new String(buffer) + "]");
				logger.error("Request  [" + new String(headBuffer) + "]");
				
				System.out.println(DateUtils.getNow()+":"+remoteIP);
				Response resp = new DefaultResponse();
				resp.setErrorCode(Constant.CODE_HEADER_ERR);
				resp.setErrorMsg(Constant.MSG_HEADER_ERR);
				resultJson = genJsonResp(resp);
				return resultJson;
			}
			//然后再将头部key=value的字符串数组中的参数和值全部解析出来存储为headerInfo对象
			//目前定义的头有7个字段
			if (headerStrList != null) {
				for (int i = 0; i < headerStrList.length; i++) {
					String[] kvStr = headerStrList[i].split("=");
					if (kvStr != null && kvStr.length == 2) {
						if (kvStr[0].compareTo("appId") == 0) {
							headerInfo.setAppId(kvStr[1]);
						} else if (kvStr[0].compareTo("method") == 0) {
							headerInfo.setMethod(kvStr[1]);
						} else if (kvStr[0].compareTo("lang") == 0) {
							headerInfo.setLang(kvStr[1]);
						} else if (kvStr[0].compareTo("sign") == 0) {
							headerInfo.setSign(kvStr[1]);
						} else if (kvStr[0].compareTo("uuId") == 0) {
							headerInfo.setUuId(kvStr[1]);
						} else if (kvStr[0].compareTo("version") == 0) {
							headerInfo.setVersion(kvStr[1]);
						} else if (kvStr[0].compareTo("timestamp") == 0) {
							headerInfo.setTimestamp(kvStr[1]);
							
							if (!checkVisitTime(kvStr[1])) {
								//统一的返回对象封装
								Response resp = null;
								resp = new DefaultResponse();
								resp.setErrorCode(Constant.CODE_TIME_ERROR);
								resp.setErrorMsg(Constant.MSG_TIME_ERROR);
								resultJson = genJsonResp(resp);
								
								logger.debug("Response:" + resultJson);
								
								System.out.println(remoteIP);
								return resultJson;
							}
							
							
						}
					}
				}
			}
			try {
				
				// logger.debug("headerInfo:"						+ headerInfo.toString());
			//  UUID uu=UUID.fromString(UUID.randomUUID().toString());
			//  logger.debug("uu:"						+ uu.toString());
			//	logger.debug("uu:"						+ uu.getLeastSignificantBits());
			//	//校验header签名信息
				//先屏蔽头校验
				 if(1==1)
				{
					HeaderCheckImpl.execute(headerInfo);
				}
				
				
				//获取准备实现的对象方法名
				String method = headerInfo.getMethod();
				
				/*
				//生成实现类的名称
				StringBuffer implClassName = new StringBuffer();
				implClassName.append("com.health.mapp.impl.");
				implClassName.append(toUpperCaseInitial(method));
				implClassName.append("Impl");*/

				//对应的请求bean
				/*StringBuffer beanClassName = new StringBuffer();
				beanClassName.append("com.health.mapp.bean.");
				beanClassName.append(toUpperCaseInitial(method));
				beanClassName.append("Req");*/

				//统一的返回对象封装
				Response resp = null;
				try {
					
					//logger.debug("implClassName: "							+ implClassName.toString());
					//反射生成方法类对象
					/*Class<?> methodClass = Class.forName(implClassName
							.toString());*/
					
					
					//生成实际调用类的对象实例
					ActionInterface action = (ActionInterface) SpringContextUtil.getBean(method);

					//logger.debug("beanClassName: "							+ beanClassName.toString());
					//反射生成请求类对象
					//这里是一个空的请求模板
					
					String beanClassName = action.getClass().getName().replace(".impl.", ".bean.").replace("Impl", "Req");
					Class<?> reqClass = Class.forName(beanClassName);
					
					
		 
					 //System.out.println("map="+map.toString()); 
					//对象映射器
					ObjectMapper objectMapper = new ObjectMapper();
					objectMapper.disable(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES);  
					objectMapper.configure(SerializationConfig.Feature.FAIL_ON_EMPTY_BEANS, false);
					
					//要映射为的对象
					Object jsonBean = null;

					try {
						
						
						//将传入的key=value
					      StringBuffer sb = new StringBuffer();
					      //目前还没清楚为什么字节数组不能直接进行对象转换，所以先用字符串进行处理
					 	 for(int i=0;i<jsonBuffer.length;i++)
					 	 {
					 		//logger.debug("jsonBuffer-"+i+":"+ (char)jsonBuffer[i]);
					 		sb.append((char)jsonBuffer[i]);
					 	 }
					 	//logger.debug("sb: "	+ sb);
						// String jsonString = "{\"imsi\":\"122\", \"imei\":12212}";
						// logger.debug("jsonBuffer:"+ jsonBuffer.toString());
					 	 
					 	 
					 	   String  allStr=new String(buffer,"UTF-8");
					 	   //logger.debug("allStr:"+allStr);
					 	 
					 	
							ReqLog message =null;	 
							//先进先出队列
							String key="queen_req_message";
							String result=null;
							 
							try
							{
								
								RedisClient.lpushDataToRedis(key, allStr);
								//String s1d=(String) RedisClient.rpopDataOutRedis(key);
								//logger.debug("s1d"+s1d);
								//long a = System.currentTimeMillis();
								 
							}
							catch(Exception e)
							{
							/*	IReqLogService iReqLogService =(IReqLogService) SpringContextUtil.getBean("reqLogService");
								
							 
							//	message= RongCloudHelper.parseObject(allXml);
								logger.error(e.getCause()); 
							//	System.out.println("message:"+message);
								
						 
								iReqLogService.insert(message);*/
								//long b = System.currentTimeMillis();
								 
							}
							
							
					 	 
					 	 
					 	 
						jsonBean = objectMapper.readValue(new String(jsonBuffer,"UTF-8"), reqClass);
						//logger.debug("Request method: "	+ headerInfo.getMethod());
					//	logger.debug(String.format("Request bean: [%s]", request.getSession().getId() ));
						CommonsUtils.dumpObject(logger, jsonBean);
						headerInfo.setHttpRequest(getRequest());
						
						//处理业务
						resp = action.execute(headerInfo, jsonBean);
						
						
					} catch (JsonParseException e) {
						resp = new DefaultResponse();
						resp.setErrorCode(Constant.CODE_REQ_JSON_FORMAT_ERR);
						resp.setErrorMsg(Constant.MSG_REQ_JSON_FORMAT_ERR);
						resultJson = genJsonResp(resp);
						e.printStackTrace();
						logger.error(Constant.MSG_REQ_JSON_FORMAT_ERR +"["
								+ headerInfo.getMethod() + "]"
								+ new String(jsonBuffer));
					/*	System.out.println(Constant.MSG_REQ_JSON_FORMAT_ERR+"["
								+ headerInfo.getMethod() + "]"
								+ new String(jsonBuffer));*/
					} catch (JsonMappingException e) {
						resp = new DefaultResponse();
						resp.setErrorCode(Constant.CODE_REQ_JSON_FORMAT_ERR);
						resp.setErrorMsg(Constant.MSG_REQ_JSON_FORMAT_ERR);
						resultJson = genJsonResp(resp);
						e.printStackTrace();
						logger.error(Constant.MSG_REQ_JSON_FORMAT_ERR+"["
								+ headerInfo.getMethod() + "]"
								+ new String(jsonBuffer));
					/*	System.out.println(Constant.MSG_REQ_JSON_FORMAT_ERR+"["
								+ headerInfo.getMethod() + "]"
								+ new String(jsonBuffer));*/
					} catch (IOException e) {
						resp = new DefaultResponse();
						resp.setErrorCode(Constant.CODE_REQ_JSON_FORMAT_ERR);
						resp.setErrorMsg(Constant.MSG_REQ_JSON_FORMAT_ERR);
						resultJson = genJsonResp(resp);
						e.printStackTrace();
						logger.error(Constant.MSG_REQ_JSON_FORMAT_ERR+"["
								+ headerInfo.getMethod() + "]"
								+ new String(jsonBuffer));
					/*	System.out.println(Constant.MSG_REQ_JSON_FORMAT_ERR+"["
								+ headerInfo.getMethod() + "]"
								+ new String(jsonBuffer));*/
					} catch (Exception e) {
						resp = new DefaultResponse();
						resp.setErrorCode(Constant.CODE_REQ_MAPP_ERR);
						resp.setErrorMsg(Constant.MSG_REQ_MAPP_ERR);
						resultJson = genJsonResp(resp);
						logger.error(Constant.MSG_REQ_MAPP_ERR
								+ e.getLocalizedMessage());
						e.printStackTrace();
						/*System.out.println(Constant.MSG_REQ_JSON_FORMAT_ERR+"["
								+ headerInfo.getMethod() + "]"
								+ new String(jsonBuffer));*/
					}
					
					//处理为json 
					resultJson = genJsonResp(resp);
				
				
					
				} catch (ClassNotFoundException e) {
					resp = new DefaultResponse();
					resp.setErrorCode(Constant.CODE_REQ_METHOD_NOT_SUPPORT);
					resp.setErrorMsg(Constant.MSG_REQ_METHOD_NOT_SUPPORT);
					resultJson = genJsonResp(resp);
					logger.error(Constant.MSG_REQ_METHOD_NOT_SUPPORT + headerInfo.getMethod());
				}

			} catch (MappException e) {
				e.printStackTrace();
				logger.error("MappException");
				resultJson = genJsonResp(e.result());
			}
		} 
		else {
			//没有头部
			//直接返回请求方法为空，头部解析错误
			Response resp = new DefaultResponse();
			resp.setErrorCode(Constant.CODE_HEADER_ERR);
			resp.setErrorMsg(Constant.MSG_HEADER_ERR);
			logger.error(Constant.MSG_HEADER_ERR);
			logger.error("ip:[" + remoteIP + "]");
			logger.error("Request  [" + new String(buffer) + "]");
			resultJson = genJsonResp(resp);
			
		}
		
		//logger.debug(String.format("RESP: %s[%s]", resultJson, request.getSession().getId() ));
		
		//如果是加密版本，需要将返回的数据进行加密再返回
		if (null != headerInfo.getVersion() && true == headerInfo.getVersion().equalsIgnoreCase("110")) {
			try {
				int number = Integer.valueOf(headerInfo.getTimestamp().substring(10));
				int index = number % 10;
				String key = SecureUtil.getCryptKey(SecureUtil.getChallenge(index));
				byte[] cryptedBuffer = SecureUtil.AESEncrypt(resultJson.getBytes("UTF-8"), key.getBytes(), useECBCrypto);
				resultJson = new String(Base64.encodeBase64(cryptedBuffer));
//				logger.debug("cryptedResponse=" + resultJson);
			} catch (Exception e) {
				e.printStackTrace();
				resultJson = "";
			}
		}
		logger.debug("Response:" + resultJson);
		return resultJson;
	}

	/**
	 * @param resp
	 * @return
	 *//*
	public static String genJsonResp(Response o) {
		String result = null;
		ObjectMapper objectMapper = new ObjectMapper();
		//版本2.x
         //		Jackson 序列化 如何让为NULL的属性不参与序列化
		objectMapper.setSerializationInclusion(Inclusion.NON_NULL); 
		JsonGenerator jsonGenerator = null;
		ByteArrayOutputStream out = null;
		try {
			out = new ByteArrayOutputStream();

			//
			jsonGenerator = objectMapper.getJsonFactory().createJsonGenerator(
					out, JsonEncoding.UTF8);
			jsonGenerator.writeObject(o);
			result = out.toString("UTF-8");
			out.flush();
			out.close();
		} catch (IOException e1) {
			e1.printStackTrace();
			result = "{\"errorCode\":100,\"errorMsg\":\"System error.\"}";
		}
		return result;
	}
	*/
	
	/**
	 * @param resp
	 * @return
	 */
	public static String genJsonResp(Response o) {
		
		return	JSONArray.toJSONString(o, SerializerFeature.DisableCircularReferenceDetect);
		//return JSONArray.toJSONString(o);
	}
	
	/**
	 * @param srcString
	 * @return
	 */
	private static String toUpperCaseInitial(String srcString) {
		StringBuilder sb = new StringBuilder();
		sb.append(Character.toUpperCase(srcString.charAt(0)));
		sb.append(srcString.substring(1));
		return sb.toString();
	}
	
	
	private final static int requestTimeOut = 43200;
	
	private static  boolean checkVisitTime(String time){
		
		Date now = DateUtils.getDatetime();
		try {
			Date visitTime = DateUtils.parseDatetime(time, "yyyyMMddHHmmss");
			
			long interval = (now.getTime() -visitTime.getTime())/1000;
			
			if(Math.abs(interval)<requestTimeOut){
				return true;
			}else{
				return false;
			}
			
		} catch (ParseException e) {
			// TODO Auto-generated catch block
			//e.printStackTrace();
			return false;
		}	
		

	}
}
